package thread;

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

//循环队列模拟阻塞队列
class MyBlockingQueue{
    private int[] item = null;
    private int size = 0;
    private int head = 0;
    private int tail = 0;
    //无参构造，默认开空间为100
    public MyBlockingQueue(){
        this(100);
    }
    //有参构造，队列的空间为capacity
    public MyBlockingQueue(int capacity) {
        this.item = new int[capacity];
    }
    //带阻塞的入队
    public void put(int elem) throws InterruptedException {
        synchronized (this){
            // 此处最好使用while，因为被消费者的 notifyAll() 唤醒后，该生产线程不一定抢到锁，
            // 锁可能被其它生产线程抢到，size 可能发生了变化，当该线程抢到锁的时候，需要再次检查队列是否是满的，
            // 满了，继续 wait() 阻塞，未满则相队列添加元素
            while(size == item.length){
                this.wait();
            }

            item[tail++] = elem;
            if(tail >= item.length){
                tail = 0;
            }
            size++;
            this.notifyAll();
        }
    }

    public int take() throws InterruptedException {
        int ret = 0;
        synchronized (this){
            while(size == 0){
                wait();
            }
            ret = item[head++];
            if (head >= item.length){
                head = 0;
            }
            size--;
            notifyAll();
        }
        return ret;
    }
}

public class ThreadDemo15 {
    //生产者消费者
    public static void producerAndCustomer() throws InterruptedException {
        //阻塞队列
        MyBlockingQueue queue = new MyBlockingQueue(1000);
        //消费线程
        Thread customer = new Thread(()->{
            while(true){
                try {
                    int elem = queue.take();
                    System.out.println("消费元素：" + elem);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "消费者");
        //启动消费线程
        customer.start();

        //生产线程
        Thread producer = new Thread(()->{
            Random random = new Random(System.currentTimeMillis());
            while(true){
                try {
                    int elem = random.nextInt(1000);
                    System.out.println("生产元素：" + elem);
                    queue.put(elem);
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "生产者");
        //启动生产线程
        producer.start();

        customer.join();
        producer.join();

    }

    public static void test() throws InterruptedException {
        MyBlockingQueue myBlockingQueue = new MyBlockingQueue(1000);
        Random random = new Random(System.currentTimeMillis());
        Runnable producerRunnable = new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        int elem = random.nextInt(1000);
                        System.out.println(Thread.currentThread().getName() + " 生产元素：" + elem);
                        myBlockingQueue.put(elem);
                        //Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };

        Runnable customerRunnable = new Runnable() {
            @Override
            public void run() {
                while(true){
                    try {
                        int elem = myBlockingQueue.take();
                        System.out.println(Thread.currentThread().getName() + " 消费元素：" + elem);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        int producerCount = 3;
        Thread[] producers = new Thread[producerCount];
        for(int i = 0; i < producerCount; i++){
            String name = "生产者" + (i + 1);
            producers[i] = new Thread(producerRunnable, name);
            producers[i].start();
            //producers[i].join();
        }

        int customerCount = 3;
        Thread[] customers = new Thread[customerCount];
        for(int i = 0; i < customerCount; i++){
            String name = "消费者" + (i + 1);
            customers[i] = new Thread(customerRunnable, name);
            customers[i].start();
            //customers[i].join();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        //producerAndCustomer();

        test();

    }
}


